package cn.ii8080.i8.gateway.server.filter;

import cn.ii8080.i8.gateway.server.util.RedisUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.util.UUID;

/**
 * 请求数据带上凭证编号
 * https://i8-server/i8/i8-cas/123123?r2=4ddc5862-890e-49cb-904c-0a90045b7a50
 * 获得请求凭证
 * https://i8-server/i8/i8-cas/123123?r1
 * 防重放攻击
 */
@Component
public class ReplayAttackGatewayFilterFactory extends AbstractGatewayFilterFactory {
    public static String R_CODE_REDIS_KEY = "i8:gateway:R:%s";
    public static String RID_1 = "r1";
    public static String RID_2 = "r2";
    @Autowired
    private RedisUtils redisUtils;
    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String path = request.getPath().toString();
            String r2 = request.getQueryParams().getFirst(RID_2);
            if (StringUtils.isEmpty(r2)) {
                HttpCookie first = request.getCookies().getFirst(RID_2);
                if (ObjectUtils.isNotEmpty(first)) {
                    r2 = first.getValue();
                }
            }
            if (request.getQueryParams().containsKey(RID_1)) {
                //获得请求凭证
                String uuid = UUID.randomUUID().toString();
                String r1Key = String.format(R_CODE_REDIS_KEY, uuid);
                redisUtils.set(r1Key, path, 10);
                ServerHttpResponse response = exchange.getResponse();
                response.setStatusCode(HttpStatus.OK);
                response.getHeaders().add("Content-Type", "text/plain");
                DataBuffer buffer = response.bufferFactory().wrap(uuid.getBytes());
                ResponseCookie.ResponseCookieBuilder r2Cookie = ResponseCookie.from(RID_2, uuid).maxAge(10);
                ResponseCookie r2CookieBuild = r2Cookie.build();
                response.addCookie(r2CookieBuild);
                return response.writeWith(Mono.just(buffer));
            } else if (StringUtils.isNoneEmpty(r2)) {
                //验证请求凭证
                String r2Key = String.format(R_CODE_REDIS_KEY, r2);
                Object r2Object = redisUtils.get(r2Key);
                if (ObjectUtils.isEmpty(r2Object)) {
                    ServerHttpResponse response = exchange.getResponse();
                    response.setStatusCode(HttpStatus.ACCEPTED);
                    return response.setComplete();
                }
                redisUtils.del(r2Key);
                String r2Path = r2Object.toString();
                if (ObjectUtils.isEmpty(r2Path)) {
                    ServerHttpResponse response = exchange.getResponse();
                    response.setStatusCode(HttpStatus.ACCEPTED);
                    return response.setComplete();
                }
                if (path.equals(r2Path)) {
                    return chain.filter(exchange);
                } else {
                    ServerHttpResponse response = exchange.getResponse();
                    response.setStatusCode(HttpStatus.ACCEPTED);
                    return response.setComplete();
                }
            } else {
                //无请求凭证
                ServerHttpResponse response = exchange.getResponse();
                response.setStatusCode(HttpStatus.NON_AUTHORITATIVE_INFORMATION);
                return response.setComplete();
            }
        };
    }
}
